package cl.xintec.utils.object
{	
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	import flash.xml.XMLDocument;
	import flash.xml.XMLNode;
	import flash.xml.XMLNodeType;
	
	import mx.collections.ArrayCollection;
	import mx.rpc.xml.SimpleXMLDecoder;
	import mx.utils.ObjectProxy;
	import mx.utils.ObjectUtil;
	import mx.utils.StringUtil;	

	public class XMLtoObject10
	{
		public function XMLtoObject10(makeObjectsBindable:Boolean=false)
		{
			this.makeObjectsBindable = makeObjectsBindable;
		}


		public function decodeToObject(result:String):Object {
			var xmlDoc:XMLDocument;
            var resultObj:Object;
			var object:Object;

			xmlDoc = new XMLDocument(result);
            resultObj = xmlToObject(xmlDoc);
            
            for each (var obj:Object in resultObj) {
				// Siempre viene un solo objeto
				object = obj;	
            }
            
            return object;
		}
		

	    /**
	     *  Converts a tree of XMLNodes into a tree of ActionScript Objects.
	     */		
		public function xmlToObject(dataNode:XMLNode):Object {
        var result:Object;
        var isSimpleType:Boolean = false;

        if (dataNode == null)
            return null;

        // Cycle through the subnodes
        var children:Array = dataNode.childNodes;
        if (children.length == 1 && children[0].nodeType == XMLNodeType.TEXT_NODE)
        {
            // If exactly one text node subtype, we must want a simple
            // value.
            isSimpleType = true;
            
            if (children[0].nodeValue is String && StringUtil.trim(String(children[0].nodeValue)) == "") {
            	result = children[0].nodeValue.toString();
            } else 
            	result = SimpleXMLDecoder.simpleType(children[0].nodeValue);
        }
        else if (children.length > 0)
        {
            result = {};
            if (makeObjectsBindable)
                result = new ObjectProxy(result);

            for (var i:uint = 0; i < children.length; i++)
            {
                var partNode:XMLNode = children[i];

                // skip text nodes, which are part of mixed content
                if (partNode.nodeType != XMLNodeType.ELEMENT_NODE)
                {
                    continue;
                }

                var partName:String = SimpleXMLDecoder.getLocalName(partNode);
                var pattern:RegExp = /__/g;
                partName = partName.replace(pattern, "_");
                
                var partObj:Object = xmlToObject(partNode);

                // Enable processing multiple copies of the same element (sequences)
                
                var oriPartName:String = partName;
                var refClass:Class;
                var instance:Object;
                var isArray:Boolean = false;
                
                if (partName.indexOf(_nsBus) != -1) {                	
                	partName = partName.replace(_nsBus, _nsVo);
                	
                	if (partName.indexOf("-array") != -1) {
                		oriPartName = partName.substring(0, partName.length-"-array".length);
                		partName = partName.replace(_nsVo + ".", _nsVo + ".ArrayOf");
                		partName = partName.substring(0, partName.length-"-array".length);
                		
						refClass = getDefinitionByName(partName) as Class;
						instance = new refClass();

						var constructor:String = partName.substring(_nsVo.length,partName.length); 

						if (partObj != null && (partObj != ""))
							partObj = partObj[oriPartName];
						
						isArray = true;                  		
                		                		
                	} else {
                	
						refClass = getDefinitionByName(partName) as Class;
						instance = new refClass();
						
	                	var descriptionXml:XML = describeType(instance);
	                	//var descriptionObject:Object = ObjectUtil.getClassInfo(instance);
	                	
	                	//for each (var prop in descriptionObject.properties) {
	                	for each (var prop:Object in descriptionXml.variable) {
	                		if (ObjectUtil.isSimple(partObj[prop.@name]))
	                			if (prop.@type != "Array") {
	                				instance[prop.@name] =  partObj[prop.@name];
	                			} else {
	                				//Arreglo vacío
	                				instance[prop.@name] =  new Array();
	                			}
	                		else {
	                			//instance[prop.@name] =  partObj[prop.@name];
	                			
	                			var obj:Object = partObj[prop.@name];
	                			
	                			for each (var arr:Object in obj) {
	                				var tinst:String = ObjectUtil.getClassInfo(instance[prop.@name]).name;
	                				var tarr:String = ObjectUtil.getClassInfo(arr).name;
	                				//if ((ObjectUtil.getClassInfo(instance[prop.@name]).name == "Array") && (ObjectUtil.getClassInfo(arr).name != "Array")) {
	                				if ((prop.@type == "Array") && (tarr != "Array")) {
	                					instance[prop.@name] = [arr];
	                				} else {
	                					instance[prop.@name] = arr;
	                				}
	                			}
	                			
	                		}
	                	}

	                	partObj = instance;
	                }

                }
                
                var existing:Object = result[partName];
                if (existing != null)
                {
                    if (existing is Array)
                    {
                        existing.push(partObj);
                    }
                    else if (existing is ArrayCollection)
                    {
                        existing.source.push(partObj);
                    }
                    else
                    {
                        existing = [existing];
                        existing.push(partObj);

                        if (makeObjectsBindable)
                            existing = new ArrayCollection(existing as Array);

                        result[partName] = existing;
                    }
                }
                else
                {
                	if (partObj == "") {
                		result[partName] = null;
                	} else if (isArray && (ObjectUtil.getClassInfo(partObj).name != "Array")) {
                		result[partName] = [partObj];
                	} else {
                		result[partName] = partObj;
                	}
                }
            }
        } else {
        	result = "";
        }

        return result;
			
		}
		
		private var makeObjectsBindable:Boolean;
		private var _nsBus:String = "cl.bcx.scotiabank.gploc.ingreso.model.business";
		private var _nsVo:String = "cl.bcx.scotiabank.gploc.ingreso.view.ws";

		public function set nsBus(value:String):void {
			_nsBus = value;
		}

		public function set nsVo(value:String):void {
			_nsVo = value;
		}


	}
}